package com.chub.study.modules.service.impl;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chub.study.modules.annotation.DictTranslate;
import com.chub.study.modules.annotation.LogRecord;
import com.chub.study.modules.dto.StudInfoDTO;
import com.chub.study.modules.entity.PsnInfo;
import com.chub.study.modules.entity.PsnInfoDTO;
import com.chub.study.modules.entity.TClassInfo;
import com.chub.study.modules.entity.TStudInfo;
import com.chub.study.modules.mapper.TStudInfoMapper;
import com.chub.study.modules.service.TClassInfoService;
import com.chub.study.modules.service.TStudInfoService;
import com.chub.study.util.FindUtils;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.ValidationException;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;

/**
 * <p>
 * 学生信息表 服务实现类
 * </p>
 *
 * @author chub
 * @since 2021-08-26
 */
@Service
@Slf4j
public class TStudInfoServiceImpl extends ServiceImpl<TStudInfoMapper, TStudInfo> implements TStudInfoService {

    @Autowired
    TStudInfoMapper studInfoMapper;

    @Autowired
    TClassInfoService classInfoService;

    private int scheduledCount = 0;

    @Override
    public List<TStudInfo> getStudListByProcedure(String in_bjbh) {
        // JdbcType.DECIMAL
        // JdbcType
        return studInfoMapper.getStudListByProcedure(in_bjbh);
    }

    @Override
    public List<Map<String, Object>> getStudListMapByProcedure(String in_bjbh) {
        return studInfoMapper.getStudListMapByProcedure(in_bjbh);
    }

    @Override
    public TStudInfo studentRegister(TStudInfo studInfo) throws Exception {
        if (ObjectUtil.isEmpty(studInfo)) {
            return null;
        }
        String xsbh = studInfo.getXsbh();
        if (StrUtil.isBlank(xsbh)) {
            throw new ValidationException("学生编号(xsbh)不能为空。");
        }
        String xsxm = studInfo.getXsxm();
        if (xsxm == null || xsxm.length() == 0) {
            throw new ValidationException("学生姓名(xsxm)不能为空。");
        }
        String bjbh = studInfo.getBjbh();
        if (bjbh == null || bjbh.length() == 0) {
            throw new ValidationException("学生班级编号(bjbh)不能为空。");
        }

        String phoneNum = studInfo.getPhone();
        if (phoneNum == null || phoneNum.length() == 0) {
            throw new ValidationException("手机号码(phone)格式错误。");
        }

        // 手机归属地编号
        String areaCode = FindUtils.getAreaCode(phoneNum);
        // 手机运营商编号
        String operCode = FindUtils.getOperatorCode(phoneNum);

        try {
            TClassInfo classInfo = classInfoService.getById(bjbh);
            if (classInfo != null) {
                studInfoMapper.insert(studInfo);
            }
        } catch (Exception e) {
            throw new SQLException( "SQLException thrown " + e.getMessage());
        }

        return studInfo;
    }

    @Override
    @DictTranslate
    public List<TStudInfo> getStudListByMap(Map<String, String> studInfo) {
        return studInfoMapper.getStudListByMap(studInfo);
    }

    /**
     * @description : 大数据量时，分批次插入数据库
     *
     * @param  : totalCnt   总数据量
     * @param  : batchNum   每批数据量
     * @return : int
     * @author : chub
     * @date   : 2024-03-28 16:25
     */
    @Override
    public int batchInsert(int totalCnt, int batchNum) {

        int year = 1950;
        int num  = 1000;
        Random random = new Random();
        // int randomNumber = random.nextInt(10); // 生成一个0到9的随机整数
        String[] arrStr = {"A01", "A02", "A07"};

        List<TStudInfo> stdList = new ArrayList<>();
        for (int i = 0; i < totalCnt; i++) {
            TStudInfo studInfo = new TStudInfo();
            studInfo.setXsbh(StrUtil.format("{}{}", year, num++));
            studInfo.setXsxm("");
            studInfo.setXsnl(random.nextInt(20) + 20);
            studInfo.setXsxb(StrUtil.toString(random.nextInt(2)));
            studInfo.setBzje(new BigDecimal(random.nextInt(100)));
            studInfo.setBjbh(RandomUtil.randomEle(arrStr));
            studInfo.setCsri(LocalDate.now());
            studInfo.setPhone("");
            stdList.add(studInfo);

            if (num >= 5000) {
                num = 1000;
                year++;
            }

        }

        log.info("要插入的学生信息数量 = {}, 每批记录数量 = {}", totalCnt, batchNum);
        int succNum = 0;
        List<List<TStudInfo>> partition = ListUtil.partition(stdList, batchNum);
        for (List<TStudInfo> studInfoList : partition) {
            int respCode = studInfoMapper.batchInsert(studInfoList);
            log.info("log  插入的学生信息数量 = {}", respCode);
            succNum += respCode;
        }
        log.info("成功插入的学生信息的总量 = {}。", succNum);
        return succNum;
    }


    /**
     * 执行定时任务。
     *     @Scheduled(fixedRate = 3000) 上一次开始执行时间点之后 3 秒再执行（fixedRate属性：定时任务开始后再次执行定时任务的延时（需等待上次定时任务完成），单位毫秒）。
     *
     *     @Scheduled(fixedDelay = 3000) 上一次执行完毕时间点之后 3 秒再执行（fixedDelay属性：定时任务执行完成后再次执行定时任务的延时（需等待上次定时任务完成），单位毫秒）。
     *
     *     @Scheduled(initialDelay = 1000, fixedRate = 3000) 第一次延迟1秒后执行，之后按fixedRate 的规则，
     *     每 3 秒执行一次（ initialDelay 属性：第一次执行定时任务的延迟时间，需配合 fixedDelay或者 fixedRate 来使用）。
     *
     *     @Scheduled(cron="0 0 2 1 * ? * ") 通过 cron 表达式定义规则。
     *     cron 表达式是一个字符串，该字符串由 6 个空格分为 7 个域，每一个域代表一个时间含义。
     *     通常定义 “年” 的部分可以省略，实际常用的 Cron 表达式由前 6 部分组成。格式如下：
     *     [秒] [分] [时] [日] [月] [周] [年]
     *
     *
     */
    @ApiOperation(value = "执行定时任务")
    // @PostMapping ("/scheduledTask")
    // @Scheduled(cron="0 0/2 * * * * ")    // 从项目启动后的首个00秒开始，每隔2分钟执行一次
    @Scheduled(fixedRate = 1000*60*5)   // 从项目启动后的，每隔300秒执行一次
    public void scheduledTask() {
        log.info("执行定时任务次数 = {} ", ++scheduledCount);

    }

    /**
     * 分页查询
     *
     * @param reqDto
     * @return IPage<PsnInfo>
     */
    @LogRecord(methodDesc = "分页查询")
    @Transactional(readOnly = true)
    @Override
    public IPage<TStudInfo> selectStudListByPage(StudInfoDTO reqDto) {
        IPage<TStudInfo> selectPage = studInfoMapper.selectStudListByPage(reqDto.toPage(), reqDto);
        log.info("resultPage：{}", JSON.toJSONString(selectPage));
        return selectPage;
    }


}
